#pragma once

#include "Base\Setting.h"

namespace ShRp
{
	namespace Base
	{
		class Settings
		{
		public:
			static bool Init();
			static void Terminate();

			static void Load(const char* _Path);
			static void Save(const char* _Path);
			static void ParseLine( std::string _Line, int _LineNumber );
			template<class U> static U ParseType( std::string _ValStr, U (*_ConversionFunc)(const char*) )
			{
				U val = _ConversionFunc(_ValStr.c_str());
				return val;
			}
			template<class _ReturnType, class _ConversionType>
			static _ReturnType ParseVecType( std::string _ValStr, int _Num, _ConversionType (*_ConversionFunc)(const char*) )
			{
				_ReturnType val = _ReturnType(0);
				// Extract parts
				for(int i = 0; i < _Num; ++i)
				{
					std::string subValStr = _ValStr.substr(0, _ValStr.find(", "));
					if(subValStr.length() == 0)
						subValStr = _ValStr;
					else
						_ValStr = _ValStr.substr(_ValStr.find(", ")+2);
#pragma warning(push)
#pragma warning(disable:4244)
					val.data[i] = _ConversionFunc(subValStr.c_str());
#pragma warning(pop)
				}
				return val;
			}
			template<class U> static std::string StringifyIntType( U _Val )
			{
				char buffer[128];
				_itoa_s(_Val, buffer, 128, 10);
				return std::string(buffer);
			}
			template<class U> static std::string StringifyFloatType( U _Val )
			{
				char buffer[128];
				_gcvt_s(buffer, 128, _Val, 10);
				return std::string(buffer);
			}
			template<class U>
			static std::string StringifyIntVecType( U _Val, int _Num)
			{
				std::string retStr = "";

				char buffer[128];
				_itoa_s(_Val.data[0], buffer, 128, 10);
				retStr += std::string(buffer);
				for(int i = 1; i < _Num; ++i)
				{
					retStr += std::string(", ");
					_itoa_s(_Val.data[i], buffer, 128, 10);
					retStr += std::string(buffer);
				}
				return retStr;
			}
			template<class U>
			static std::string StringifyFloatVecType( U _Val, int _Num)
			{
				std::string retStr = "";

				char buffer[128];
				_gcvt_s(buffer, 128, _Val.data[0], 10);
				retStr += std::string(buffer);
				for(int i = 1; i < _Num; ++i)
				{
					retStr += std::string(", ");
					_gcvt_s(buffer, 128, _Val.data[i], 10);
					retStr += std::string(buffer);
				}
				return retStr;
			}

			template<class U> static U GetSetting(char* _Name)
			{
				return GetSetting<U>(std::string(_Name));
			}
			template<class U> static U GetSetting(std::string _Name)
			{
				StringSettingMap::iterator settingIt = m_Settings.find(_Name);
				if(settingIt == m_Settings.end())
				{
					Warn("Invalid setting \"%s\" requested.\n", _Name.c_str());
					return U();
				}
				Setting* setting = settingIt->second;

				return setting->GetValue<U>();
			}
			template<class U> static void SetSetting(std::string _Name, const U& _Value, const Setting::Type::E _Type )
			{
				StringSettingMap::iterator settingIt = m_Settings.find(_Name);
				Setting* setting;
				if(settingIt == m_Settings.end())
				{
					setting = new Setting();
					m_Settings.insert(StringSettingPair(_Name, setting));
				}
				else
					setting = settingIt->second;

				setting->SetValue<U>(_Value, _Type);
			}
		private:
			static StringSettingMap m_Settings;
		};
	};
};